﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Web;
using System.Data.Linq;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using Common;
namespace DataAccess
{
    public interface IEntityBaseDAL<TEntity>
    {

        void AddEntity(TEntity model);
        void AddEntityList(IEnumerable<TEntity> list);

        void UpdateEntity(TEntity model);
        void UpdateEntityList(IEnumerable<TEntity> list);

        void DeleteEntity(TEntity model);
        void DeleteEntityList(IEnumerable<TEntity> list);

        List<TEntity> GetEntityAll();
        TEntity GetEntityFromKey(object key);

    }


    public abstract class EntityDALBase<TEntity, TContext> : IEntityBaseDAL<TEntity>
        where TEntity : class,new()
        where TContext : System.Data.Entity.DbContext, new()
    {
        public EntityDALBase() { }

        public EntityDALBase(TContext context)
        {
            this._context = (context as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext;
        }

        //获取主键

        #region Context
        private ObjectContext _context;

        public virtual string ContextKey { get { { return "____EntityContextCache"; } } }

        /// <summary>
        /// 此Context用于操作添加更新删除操作
        /// </summary>
        public virtual ObjectContext Context
        {
            get
            {
                if (_context == null)
                {

                    HttpContext httpContext = HttpContext.Current;
                    if (httpContext != null)
                    {
                        _context = (ObjectContext)httpContext.Items[ContextKey];
                        if (_context == null)
                        {
                            _context = new ObjectContext("name = HrEntities");
                            httpContext.Items.Add(ContextKey, _context);
                        }
                    }
                    if (_context == null)
                        _context = new ObjectContext("name = HrEntities");
                }
                return _context;
            }
            set
            {
                this._context = value;
            }
        }

        private ObjectContext _queryContext;

        public virtual string ContextQueryKey { get { { return "____EntityContextQueryCache"; } } }

        /// <summary>
        /// 此Context用于查询
        /// </summary>
        public virtual ObjectContext ContextQuery
        {
            get
            {
                //if (_queryContext == null)
                //{

                //    HttpContext httpContext = HttpContext.Current;
                //    if (httpContext != null)
                //    {
                //        _queryContext = (TContext)httpContext.Items[ContextQueryKey];
                //        if (_queryContext == null)
                //        {
                //            _queryContext = new TContext();
                //            _queryContext.ObjectTrackingEnabled = false;
                //            httpContext.Items.Add(ContextQueryKey, _queryContext);
                //        }
                //    }
                //    if (_queryContext == null)
                //    {
                //        _queryContext = new TContext();

                //    }
                //    if (_queryContext.ObjectTrackingEnabled)
                //        _queryContext.ObjectTrackingEnabled = false;

                //}
                // return _queryContext;
                return Context;
            }
            set
            {
                this._queryContext = value;
            }
        }


        public TContext NewContext
        {
            get { return new TContext(); }
        }

        //public TContext QueryContext { get { } }


        protected ObjectSet<TEntity> TTable
        {
            get { return Context.CreateObjectSet<TEntity>(); }
        }
        #endregion

        public virtual void AddEntity(TEntity model)
        {
            ObjectSet<TEntity> objectSet = Context.CreateObjectSet<TEntity>();
            objectSet.AddObject(model);

            Context.SaveChanges();
        }

        public void AddEntityNoComplete(TEntity model)
        {
            TTable.AddObject(model);
        }

        public virtual void AddEntityList(IEnumerable<TEntity> list)
        {
            AddEntityListNoComplete(list);
            Context.SaveChanges();
        }

        public void AddEntityListNoComplete(IEnumerable<TEntity> list)
        {
            var tabel = this.TTable;
            foreach (var item in list)
                tabel.AddObject(item);
        }

        public virtual void UpdateEntity(TEntity model)
        {

            Detatch(model);
            var m = GetEntityFromEntity(this.Context, model);
            model.PropertiesCopyTo(m);
            Context.SaveChanges();
        }

        public virtual void UpdateEntityNoComplete(TEntity model)
        {
            TTable.Attach(model);
        }

        public virtual void UpdateEntityList(IEnumerable<TEntity> list)
        {

            var tabel = this.TTable;
            foreach (var item in list)
                tabel.Attach(item);

            Context.SaveChanges();
        }

        public void UpdateEntityListNoComplete(IEnumerable<TEntity> list)
        {
            var tabel = this.TTable;
            foreach (var item in list)
                tabel.Attach(item);
        }

        public virtual void DeleteEntity(TEntity model)
        {
            var tabel = this.TTable;
            tabel.DeleteObject(model);
            Context.SaveChanges();
        }

        public void DeleteEntityNoComplete(TEntity model)
        {
            var tabel = this.TTable;
            tabel.DeleteObject(model);
        }

        public virtual void DeleteEntityList(IEnumerable<TEntity> list)
        {
            var tabel = this.TTable;
            foreach (var item in list)
                tabel.DeleteObject(item);
            Context.SaveChanges();
        }

        public void DeleteEntityListNoComplete(IEnumerable<TEntity> list)
        {
            var tabel = this.TTable;
            foreach (var item in list)
                tabel.DeleteObject(item);
        }

        public virtual List<TEntity> GetEntityAll()
        {
            return this.TTable.ToList();
        }



        public ObjectQuery<TEntity> GetQueryable()
        {
            return this.TTable;
        }




        public virtual TEntity GetEntityFromKey(object key) {
            return new TEntity();
        }

        public virtual TEntity GetEntityFromEntity(ObjectContext context, TEntity model) {
            return new TEntity();
        }



        #region Detatch  辅助实体与原DataContext分离
        /// <summary>
        /// 辅助LinqToSql实体与原DataContext分离
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        public static void Detatch<T>(T entity)
        {

            Type t = entity.GetType();

            System.Reflection.PropertyInfo[] properties = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

            foreach (var property in properties)
            {

                string name = property.Name;

                if (property.PropertyType.IsGenericType &&

                property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>))
                {

                    property.SetValue(entity, null, null);

                }

            }

            System.Reflection.FieldInfo[] fields = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            foreach (var field in fields)
            {

                string name = field.Name;

                if (field.FieldType.IsGenericType &&

                field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>))
                {

                    field.SetValue(entity, null);

                }

            }

            System.Reflection.EventInfo eventPropertyChanged = t.GetEvent("PropertyChanged");

            System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging");

            if (eventPropertyChanged != null)
            {

                eventPropertyChanged.RemoveEventHandler(entity, null);

            }

            if (eventPropertyChanging != null)
            {

                eventPropertyChanging.RemoveEventHandler(entity, null);

            }

        }
        #endregion



    }
}
